封装
封装的理解
封装是属性和方法的抽象。让数据和代码成为类的过程。
对属性和方法进行定义、隔离、保护。
形成一个类对外可操作属性和方法的接口
隐藏实现细节,使得代码模块化
私有属性VS公开属性、私有方法VS公开方法
由于属性和方法都可以看作是类内部的对象,所以下面简称二者为’对象‘。
公开对象可以在类内部和外部使用
私有对象只能在类内部使用,外部直接调用时会发生AttributeError
如需定义一个私有属性,只需要在属性名中加双下划线前缀__。这种处理方法只是修改了原有属性的名字,如果非要访问私有属性和私有方法也可以,在原名字前加下划线和类名。如_Person__count
私有化从形式上保护了python类内部使用的逻辑,是一种程序员间的约定。
保留属性
也叫特殊属性,双下划线开头和结尾
为理解python类提供了统一的属性接口
属性值具有特定含义,类定义后直接使用
| 类对象的保留属性 | 描述 |
| —————- | ————————————— |
| __name__ | 类的名字 |
| __qualname__ | 以.分隔的从模块全局命名空间开始的类名称 |
| __bases__ | 类所继承的基类名称 |
| __dict__ | 类成员信息的字典 || 实例对象的保留属性 | 描述 |
| —————— | —————————————— |
| __dict__ | 对象属性信息的字典,key是属性,value是值 |
| __class__ | 类对象对象的类信息,即type信息 |
| __doc__ | 类描述,写在类定义下的首行字符串,不能继承 |
| __module__ | 类所在模块的名字 |
保留方法
也叫特殊方法,以双下划线开头和结尾的方法。
为操作python类提供了统一的方法接口
| 常用保留方法 | 对应操作 | 描述 |
| ————— | —————– | ——————————– |
| __init__() | obj = ClassName() | 初始化实例对象 |
| __del__() | del obj | 删除实例对象 |
| __repr__() | repr(obj) | 定义对象可打印字符串的函数逻辑 |
| __str__() | str(obj) | 定义对象字符串转换操作的函数逻辑 |
| __bytes__() | bytes(obj) | 字节串转换 |
| __format__() | obj.format() | 格式化输出 |
| __hash__() | hash(obj) | 哈希操作 |
| __bool__() | bool(obj) | 布尔运算 |
| __len__() | len(obj) | 对象长度 |
| __reversed__() | obj.reversed() | 对象逆序 |
| __abs__() | abs(obj) | 求绝对值 |
| __int__() | int(obj) | 整数转换 |
| __lt__() | obj1 < obj2 | 比较操作 |
| __le__() | obj1 <= obj2 | 比较操作 |
| __eq__() | obj1 == obj2 | 比较操作 |
| __ne__() | obj1 != obj2 | 比较操作 |
| __gt__() | obj1 > obj2 | 比较操作 |
| __ge__() | obj1 >= obj2 | 比较操作 |
| 等等 | | |
继承 Inheritance
什么是继承
原有的、已经写好的类,被继承的类叫做基类,也叫父类。
新构建的、继承父类的类叫做派生类,也叫子类。
父类的父类叫做超类。
一个子类可以有多个父类,这种继承方式称为多继承
扩展已存在的代码模块(类),实现了以类为单位的高抽象级别代码复用。
如何使用【[多]继承】特性
1
2
3
4
5
6# 在定义类时声明继承关系
# 父类名可以带有路径:ModuleName.BaseClassName
# 父类可以有多个,即多继承
class 类名(父类名1,父类名2,...,父类名n):
def __init__(self, 参数):
语句块子类基本可以完全拥有父类的属性和方法,并且根据需要可以重写继承来的属性和方法,也可以新增属性和方法。
所谓“基本完全拥有”指的是:子类不能继承父类的私有属性和私有方法
使用父类的类方法和类属性时,要使用父类的类名调用。或者super()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26class people():
count = 0
def __init__(self, name):
self.name = name
people.count += 1
def get_name(self):
return self.name
class man(people):
def __init__(self, name, wife):
people.__init__(self, name)
# super(man, self).__init__(name) # 也可以
self.wife = wife
def marrywho(self):
return self.wife
p0 = people('小王')
p1 = man('小张', '小李')
print(p1.get_name())
print(p1.marrywho())
print(people.count)1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39# 多继承的规则:深度优先,从左至右
# 所有属性、方法,以及super()也遵从这一原则
# 所以,多继承中父类的顺序很关键
class Cuboid(object):
def __init__(self, length, width, heigth):
self.length = length
self.width = width
self.heigth = heigth
def volume(self):
return self.heigth * self.width * self.length
def say(self):
print('本长方体的规格是%f*%f*%f' % (self.length, self.width, self.heigth))
class Iron(object):
def __init__(self, density):
self.density = density
def say(self):
print('铁的密度是%f' % self.density)
class Slab(Cuboid, Iron):
def __init__(self, length, width, heigth, density):
Cuboid.__init__(self, length, width, heigth)
Iron.__init__(self, density)
def mass(self):
return self.volume * self.density
if __name__ == '__main__':
block = Slab(2, 0.5, 0.5, 7.9e3)
print(block.mass)
block.say()判定继承关系的2个内置函数
| 函数 | 描述 |
| ———————- | —————————————————— |
| isinstance(obj, cls) | 判断对象obj是否是类cls的实例或子类实例,返回True/False |
| issubclass(cls1, cls2) | 判断类cls1是否是类cls的子类,返回True/False |
python最基础类:object
所有类定义时默认继承object类
保留属性和保留方法本质上是object类的属性和方法。
1
2
3
4
5
6
7
8
9
10
11
12print(object.__name__)
print(object.__doc__)
print(object.__bases__)
print(object.__class__)
print(object.__module__)
'''
object
The most base type
()
<class 'type'>
builtins
'''类的方法覆盖和属性覆盖
覆盖原则:就近覆盖
优先使用子类重写的属性和方法
如果子类没有重写,则去寻找父类的属性和方法
如果父类中也没有,则去寻找超类的属性和方法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39class A(object):
var = 999
def say(self):
print('AAA')
# 未重写/覆盖A的类属性var和实例方法say
class B(A):
pass
# 重写A的类属性var和实例方法say
class C(A):
var = 0
def say(self):
super().say()
print('I am C')
print(B.var)
print(C.var)
a = A()
a.say()
b = B()
b.say()
c = C()
c.say()
'''
999
0
AAA
AAA
I am C
AAA
'''
多态
多态的理解
同一操作作用于不同的对象,可以有不同的解释,产生不同的结果,这就是多态。
一种接口多种实现。
封装和继承实现的是代码重用,多态实现的是接口重用。
多态是父类使用子类的方法。
继承是子类使用父类的方法。
在C++中是通过派生类覆写基类中的虚函数型方法来实现的。简单来说就是将子类类型的指针赋值给父类类型的指针。编译时多态性通过重载实现;运行时多态性通过覆写虚成员实现。重载是对同名函数的不同参数列表实现。覆写是同名函数、同参数列表、同返回值类型的实现。
由于python是动态语言以及强大的参数传递功能,重载这一特性天然支持。当然,重载并不等同于多态。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28class Animal(object):
def run(self):
print('Animal is running...')
class Dog(Animal):
def run(self):
print('Dog is running...')
class Cat(Animal):
def run(self):
print('Cat is running...')
def run_twice(animal):
animal.run()
animal.run()
if __name__ == '__main__':
d = Dog()
c = Cat()
print(isinstance(d, Animal))
run_twice(d)
run_twice(c)对扩展开放,对修改封闭。
参数类型的多态
参数形式的多态